from urllib import urlopen, quote
import hmac
import random
import os
from commands import getoutput
import time

class client(object):
	'''
	Allows a python script to control the personal web server.
	The 2 commands useful for you: add and remove
	'''
	def __init__(self):
		self.key = self.generate_key()
		self.host = ''
		self.port = ''
		self.admsecret = self.generate_key(8)
		self.serialdb = [0]
		self.serverpid = 0
		self.seriallen = 4 # every file on the server is served out of its own folder.
		# this is to make it difficult to see other files if no direct path is given.
		# print 'Key is %s and secret is %s' % (self.key, self.admsecret)

	def start(self, host="127.0.0.1", port=8080):
		self.host = host
		self.port = str(port)
		a = [i for i in getoutput('ps a | grep .superkaramba/horovod/plugins/webserver/server.py').splitlines() if i.count('python')]
		pid = 0
		if a:
			# there is/are zomby servers running. lets kill them.
			print 'there maybe a zomby server somewhere out there.'
			for i in a:
				# print i, i.strip().split(' ',1)
				#try:
				pid = int(i.strip().split(' ',1)[0])
				#except:
				#	pid = 0
				if pid:
					print "yep, got it by the tail! Let's kill it!", pid
					os.kill(pid, 3)
			if pid:
				time.sleep(0.8) # we need this time for socket to be released.
		# python server.py ipnumber:port -s [somerandomword] -k [key that will be used for encription]
		args = ['python', os.getenv('HOME')+'/.superkaramba/horovod/plugins/webserver/server.py', self.host+':'+self.port, '-s', self.admsecret,'-k',self.key]
		self.serverpid = os.spawnvp(os.P_NOWAIT, 'python', args)

	def stop(self):
		os.kill(self.serverpid, 3)

	def __delete__(self):
		self.serverstop()

	def generate_key(self, length=32):
		'''
		We are using HMAC hashing for admin actions authentication.
		This is a funciton to generate a key composed of \w (lowercase)
		Example: 'aqghjiiqjbgykuhuzuciseooqnwknroh'
		This function is not used on the server. Just keeping it around for client integration.
		'''
		vocab = '1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM'
		a = []
		for i in range(length):
			a.append(random.choice(vocab))
		return ''.join(a)

	def hashedtext(self, text):
		return hmac.new(self.key, text).hexdigest()+'/'+text

	def tostring(self, serial):
		serial = str(serial)
		return '0'*(self.seriallen - serial.__len__()) + serial

	def add(self, filepath, filetag, serial=0, customhost=None, customport=None):
		'''
		Adds a file link to the server. Note, if you provide filetag, that will
		be used as on-server file name instead of real file name.
		
		Returns a dict type with: external, internal IP numbers and serial number given by server.
		'''
		# converting paths into url-able strings.
		filepath = quote(filepath.encode('utf8'))
		filetag = quote(filetag.encode('utf8'))
		while (not serial) and (serial in self.serialdb): # while serial = 0, or there is another copy in the db
			serial = self.tostring(random.randrange(1, pow(10,self.seriallen), 1))
		text = serial+'/'+filetag+'='+filepath
		url = 'http://'+self.host+':'+self.port+"/add/"+self.admsecret+'/'+self.hashedtext(text)
		#print "adding file with url ", url
		messages = urlopen(url)
		if customhost:
			extpath = self.formURL(filetag, serial, customhost, customport)
		else:
			extpath = ''
		return { 'externalpath':extpath,
				'internalpath':self.formURL(filetag, serial, None, None),
				'serial':serial,
				}

	def remove(self, serial):
		url = 'http://'+self.host+':'+self.port+"/remove/"+self.admsecret+'/'+self.hashedtext(self.tostring(serial))
		#print "removing file with url ", url
		messages = urlopen(url)

	def formURL(self, filetag, serial, customhost, customport):
		if customhost:
			host = customhost
		else:
			host = self.host
		if customport:
			port = str(customport)
		else:
			port = self.port
		return 'http://'+host+':'+port+"/"+self.tostring(serial)+'/'+filetag+'.html'

# follow this with:
# webserver.client.start() # optional args host="127.0.0.1", port=8080
# serial_num = webserver.client.add(realpath, filepublicname)
# webserver.client.remove(serial_num)
# webserver.client.stop()